using System;
using System.Collections.Generic;
using System.Text;
using TDUnit.Common.ScriptEngine;
using TDUnit.Common.TestData;

namespace TDUnit.MsSql
{
    public class BasicSqlScriptEngine : IScriptEngine
    {
        #region Private consts

        private const string InsertScriptFormat = "INSERT INTO [{0}] ({1}) VALUES ({2});";
        private const string DeleteScriptFormat = "DELETE FROM [{0}] WHERE {1} = {2};";
        private const string SelectScriptFormat = "SELECT {0} FROM [{1}]{2}";

        #endregion

        #region Events

        public event EventHandler<ScriptEventArgs> InsertScriptCreated;
        public event EventHandler<ScriptEventArgs> DeleteScriptCreated;
        public event EventHandler<ScriptEventArgs> AutoIdentityScriptCreated;

        #endregion

        #region Public methods

        public string GetInsertScriptForRow(Row row)
        {
            if (row == null)
                throw new ArgumentNullException("row");

            var script = string.Format(
                InsertScriptFormat,
                row.Table.Name,
                BuildColumnNameString(row),
                BuildColumnValueString(row));

            OnInsertScriptCreated(script);
            return script;

        }

        public string GetDeleteScriptForRow(Row row)
        {
            if(row == null)
                throw new ArgumentNullException("row");

            var script = string.Format(DeleteScriptFormat, row.Table.Name, FormatColumnName(row.PrimaryKeyColumn.Name),
                                 FormatColumnValue(row.PrimaryKeyColumn));
            OnDeleteScriptCreated(script);
            return script;
        }

        public string GetSelectAutoIdentityScript()
        {
            var script = "SELECT SCOPE_IDENTITY();";
            OnAutoIdentityScriptCreated(script);
            return script;
        }

        #endregion

        #region OnEvents

        protected virtual void OnInsertScriptCreated(string script)
        {
            if(InsertScriptCreated != null)
                InsertScriptCreated(this, new ScriptEventArgs(script));
        }

        protected virtual void OnDeleteScriptCreated(string script)
        {
            if (DeleteScriptCreated != null)
                DeleteScriptCreated(this, new ScriptEventArgs(script));
        }

        protected virtual void OnAutoIdentityScriptCreated(string script)
        {
            if (AutoIdentityScriptCreated != null)
                AutoIdentityScriptCreated(this, new ScriptEventArgs(script));
        }
        #endregion

        #region Helper methods

        private static string Quote(string value)
        {
            return "'" + value + "'";
        }

        private static string EscapeChars(string value)
        {
            return value.Replace("'", "''");
        }

        private static string FormatColumnName(string columnName)
        {
            return "[" + columnName + "]";
        }

        private static string FormatColumnValue(Column column)
        {
            var value = EscapeChars(column.Value);
            return column.ShouldQuote ? Quote(value) : value;
        }

        private static string BuildColumnNameString(Row row)
        {
            return BuildStringForColumns(row,
                                         (c, sb) =>
                                             {
                                                 sb.Append(FormatColumnName(c.Name));
                                                 sb.Append(',');
                                             });
        }

        private static string BuildColumnValueString(Row row)
        {
            return BuildStringForColumns(row,
                                         (c, sb) =>
                                             {
                                                 sb.Append(FormatColumnValue(c));
                                                 sb.Append(',');
                                             });
        }

        private static string BuildStringForColumns(Row row, Action<Column, StringBuilder> colAction)
        {
            var sb = new StringBuilder();
            var colList = new List<Column>(row.Columns);

            if (row.PrimaryKeyColumn.IsAutoIdentity == false)
                colList.Add(row.PrimaryKeyColumn);

            foreach (var col in colList)
            {
                colAction(col, sb);
            }

            return sb.ToString().TrimEnd(',');
        }

        private static string GetColumns(IEnumerable<string> columns)
        {
            var sb = new StringBuilder();
            foreach (var col in columns){
                sb.Append('[');
                sb.Append(col);
                sb.Append(']');
                sb.Append(',');
            }
            return sb.ToString().TrimEnd(',');
        }

        private static string CreateSelectQuery(string table, string columnString, string where)
        {
            return string.Format(SelectScriptFormat, columnString, table,
                                 string.IsNullOrEmpty(where) ? string.Empty : " WHERE " + where).Trim();
        }

        #endregion

        
    }
}